#pragma once
#include "stdafx.h"
/*
Data Format
file id
version
--chunk id (string)
--chunk size 
--chunk flag (0x0001)
--chunk data 
------chunk id (string)
------chunk size
------chunk flag (bool)
------chunk data
------chunk id (string)
------chunk size
------chunk flag (bool)
------chunk data
------chunk id (string)
------chunk size
------chunk flag (bool)
------chunk data
--chunk id (string)
--chunk size
--chunk flag (bool)
--chunk data
*/

#define GEN_VERSION(major,minor) unsigned int(unsigned short(major)<<8 | unsigned short(minor))

typedef unsigned int FileID;
typedef unsigned int VERSION;

struct FileHeader
{
	FileHeader(string n,VERSION _v)
		:version(_v),
		name(n) {}
	~FileHeader() {}
	VERSION version;
	string name;
};

class Chunk
{
public:
	typedef Vector<Chunk*>::iterator ChunkIterator;
	typedef string ChunkID;
	explicit Chunk(const Chunk&);
	explicit Chunk(ChunkID,size_t,const char*);
	explicit Chunk(ChunkID,Vector<Chunk*>);
	~Chunk();
	
	ChunkIterator GetSubChunkBegin();
	ChunkIterator GetSubChunkEnd();
	ChunkID GetID() const;
	size_t GetSize() const;
	const char* const GetData() const;
	void AddSubChunk(Chunk*);
	bool HasSubChunk() const;
	Chunk& operator=(const Chunk& tmp)
	{
		if(this!=&tmp)
		{
			this->m_id=tmp.m_id;
			this->m_size=tmp.m_size;
			this->m_bs=tmp.m_bs;
			if(this->m_bs)
			{
				this->m_subChunk=tmp.m_subChunk;
				m_data=NULL;
			}
			else
			{
				m_data=new char[m_size];
				memcpy_s(m_data,m_size,tmp.m_data,1);
				m_subChunk.clear();
			}
		}
		return *this;
	}
	
private:
	ChunkID m_id;
	size_t m_size;
	char* m_data;
	Vector<Chunk*> m_subChunk;
	bool m_bs;
};

class DataStream
{
private:
	DataStream();
public:
	DataStream(string);
	DataStream(string,string,unsigned int,Chunk*);
	~DataStream();
	void WriteBuffer(void*,size_t);
	void ReadBuffer(void*,size_t);
	void SeekToBegin();
	void SeekToEnd();
	void SeekFromBegin(size_t);
	void SeekFromCur(size_t);
	size_t GetFileLength();
	string GetChunkName() const;
	void DumpChunk(Chunk::ChunkID);
	void DumpData(const char*,size_t);
	bool Load();
	bool Save();

	Chunk* GetMainChunk() const;
private:
	Chunk* m_mainChunk;
	fstream m_file;
	FileHeader m_fileHeader;
	string m_fileName;
};


fstream& operator<<(fstream& f,Chunk* c);
fstream& operator>>(fstream& f, Chunk** c);
